/*
 * ksTest.cpp
 *
 *  Created on: Aug 5, 2011
 *      Author: wang
 */

#include "ksEncode.h"

#include <iostream>
#include <fstream>
#include "ksAtomBlockWriter.h"
#include "../ksData.h"
#include "ksCatalogAtomBlockWriter.h"
#include "ksContainerBlockWriter.h"
#include "../ksException.h"

using namespace std;

#define kSettingInfo "info:"
const int kSettingInfoLength = sizeof(kSettingInfo) - 1;

#define kSettingCover "cover:"
const int kSettingCoverLength = sizeof(kSettingCover) - 1;

#define kSettingCatalog "catalog:"
const int kSettingCatalogLength = sizeof(kSettingCatalog) - 1;

#define kSettingChapter "chapter:"
const int kSettingChapterLength = sizeof(kSettingChapter) - 1;

/*加密block数据*/
DATA* processBlockData(ksAtomBlockWriter* block, const DATA& content)
{
    DATA* pContent = (DATA*) &content;
    DATA zipContent = compress(content);
    if (zipContent.ptr && zipContent.length)
    {
        block->compress(true);
        DATA encyptContent = encrypt(zipContent);
        if (encyptContent.ptr && encyptContent.length)
        {
            block->encrypt(true);
            freeData(zipContent);
            pContent = &encyptContent;
        }
        else
        {
            pContent = &zipContent;
        }
    }
    else
    {
        DATA encyptContent = encrypt(content);
        if (encyptContent.ptr && encyptContent.length)
        {
            block->encrypt(true);
            pContent = &encyptContent;
        }
    }
    block->setData((unsigned char*) pContent->ptr, pContent->length);
    return pContent;
}

ksAtomBlockWriter* blockFromFile(unsigned short type, unsigned short id, const string& path)
{
    DATA content = dataFromFile(path.c_str());
    if (content.ptr && content.length)
    {
        ksAtomBlockWriter* block = NULL;
        if (type == kBlockCatalog)
        {
            block = new ksCatalogAtomBlockWriter();
            block->type(type);
            block->id(id);
            block->setData((unsigned char*) content.ptr, content.length);
            return block;
        }
        else
        {
            block = new ksAtomBlockWriter();

            block->type(type);
            block->id(id);

            DATA *processedContent = processBlockData(block, content);
            if (processedContent != &content)
            {
                freeData(content);
            }
            return block;
        }

    }
    else
    {
        freeData(content);
        return NULL;
    }
}

void ksEncode(const char* path, const char* result, bool main)
{
    string config(path);
    int position = config.find_last_of('\\', config.length());
    string base = config.substr(0, position);

    ifstream in;
    in.open(config.c_str(), ifstream::in);
    char szContent[256] = { 0 };

    ksContainerBlockWriter* ksfile = new ksContainerBlockWriter();
    ksfile->type(kBlockFile);
    ksfile->id(kBlockFile);

    ksContainerBlockWriter* container = NULL;
    if (main)
    {
        ksContainerBlockWriter* ksMain = new ksContainerBlockWriter();
        ksMain->type(kBlockMain);
        ksMain->id(kBlockMain);
        container = ksMain;
        ksfile->addBlock(ksMain);
    }
    else
    {
        ksContainerBlockWriter* ksPart = new ksContainerBlockWriter();
        ksPart->type(kBlockPart);
        ksPart->id(kBlockPart);
        container = ksPart;
        ksfile->addBlock(ksPart);
    }

    int lineIndex = 0;
    unsigned short id = 0;

    ksCatalogAtomBlockWriter* catalogBlock = NULL;

    while (in.good())
    {
        in.getline(szContent, 256);
        string setting(szContent);
        string file;
        unsigned short type;

        if (setting.find(kSettingInfo) == 0)
        {
            //info tag
            file = setting.substr(kSettingInfoLength);
            type = kBlockInfo;
            //id = file;
        }
        else if (setting.find(kSettingCover) == 0)
        {
            // cover tag
            file = setting.substr(kSettingCoverLength);
            type = kBlockCover;
            //id = file;
        }
        else if (setting.find(kSettingCatalog) == 0)
        {
            // catalog tag
            file = setting.substr(kSettingCatalogLength);
            type = kBlockCatalog;
            //id = file;
        }

        else if (setting.find(kSettingChapter) == 0)
        {
            // chapter tag
            file = setting.substr(kSettingChapterLength);
            type = kBlockChapter;
            //id = file;
            if (catalogBlock)
            {
                catalogBlock->updateResourceID(file, id);
            }
        }
        else
        {
            cout << "not excepted content at:" << lineIndex << " data:" << szContent << endl;
            continue;
        }

        ksAtomBlockWriter* block = blockFromFile(type, id, base + "/data/" + file);
        if (type == kBlockCatalog)
        {
            if (catalogBlock)
            {
                throw ksException("only one catalog block");
            }
            catalogBlock = (ksCatalogAtomBlockWriter*) block;
        }
        if (block)
        {
            container->addBlock(block);
        }
        lineIndex++;
        id++;
    }

    //string  result = base + "result.ks";
    ofstream output;
    output.open(result, ofstream::out | ofstream::binary);
    ksfile->prepare( 0 );
    ksfile->save(output);
    output.close();

    delete ksfile;

    cout << "success" << endl;
}

